home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / doom / ldhe-src.0 / ldhe-src / dehacked / source / dehacked.cc < prev    next >
C/C++ Source or Header  |  1995-06-02  |  20KB  |  827 lines

  1. // DeHackEd version 2.3
  2. // Written by Greg Lewis, gregl@umich.edu
  3. // If you release any versions of this code, please include
  4. // the author in the credits.  Give credit where credit is due!
  5.  
  6. #include <sys/param.h>
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <signal.h>
  11. #include <string.h>
  12.  
  13. #include "version.h"
  14. #include "dehacked.h"
  15. #include "dheinit.h"
  16.  
  17. #undef TEXT
  18. #undef WIDTH
  19. #undef HEIGHT
  20. #include "ttyobj.h"
  21.  
  22. #ifdef linux
  23. void quit(int sig)
  24. {
  25.     fprintf(stderr, "Exiting with signal %d\n", sig);
  26.     exit(0);
  27. }
  28. #else
  29. #ifdef _SGI_SOURCE
  30. void quit(int sig, ...)
  31. {
  32.     fprintf(stderr, "Exiting with signal %d\n", sig);
  33.     exit(0);
  34. }
  35. #else
  36. #error What machine are we compiling on?
  37. #endif /* _SGI_SOURCE */
  38. #endif /* linux */
  39.  
  40.  
  41. int main (int argc, char *argv[])
  42. {
  43.     EBool ExitLoop = NO;                    // Are we out of the main loop?
  44.  
  45.     /* Set up the signals to reset the console at exit */
  46.     signal(SIGHUP, quit);
  47.     signal(SIGINT, quit);
  48.     signal(SIGQUIT, quit);
  49.     signal(SIGBUS, quit);
  50.     signal(SIGSEGV, quit);
  51.     signal(SIGTERM, quit);
  52.  
  53.     // Lose suid capabilities...
  54.     setuid(getuid());
  55.  
  56.     // Initialize memory according to largest values needed
  57.     thingdata  = new unsigned long[numobj[THING][DOOM2_0]][THING_FIELDS];
  58.     sounddata  = new unsigned long[numobj[SOUND][DOOM2_0]][SOUND_FIELDS];
  59.     framedata  = new unsigned long[numobj[FRAME][DOOM2_0]][FRAME_FIELDS];
  60.     spritedata = new unsigned long[numobj[SPRITE][DOOM2_0]];
  61.     maxammodata= new unsigned long[numobj[AMMO][DOOM2_0]];
  62.     perammodata= new unsigned long[numobj[AMMO][DOOM2_0]];
  63.     weapondata = new unsigned long[numobj[WEAPON][DOOM2_0]][WEAPON_FIELDS];
  64. #ifdef TEXT_DATASIZE
  65.     textdatap  = new char[TEXT_DATASIZE];
  66. #else
  67. #error "DOOM1_9" should be replaced with the version with the largest text segment.
  68.     textdatap  = new char[size[TXT][DOOM1_9]];
  69. #endif
  70.     // Make sure we've got the necessary memory
  71.     if (thingdata  == NULL || sounddata == NULL || maxammodata == NULL ||
  72.          spritedata == NULL || framedata == NULL || perammodata == NULL ||
  73.          weapondata == NULL || textdatap == NULL)
  74.         AbortProg("in Main");
  75.  
  76.     // Initialize the thingdata to all 0's, mostly for the Clipboard.
  77.     memset(thingdata, 0, size[THING][DOOM2_0]*numobj[THING][DOOM2_0]);
  78.     getcwd(curdir, MAXPATHLEN);
  79.  
  80.     // Load config file
  81.     Parseconfigfile();
  82.  
  83.     // Check out command line arguments
  84.     if (Parsecommandline(argc, argv) == -1)
  85.         ExitLoop = YES;
  86.     else
  87.     {
  88.         // Initialize Linux specific subsystems.
  89.         if ( linux_init() < 0 )
  90.             exit(-1);
  91.         atexit(linux_end);
  92.  
  93.         // Since it's not command-line only, change to 50 line mode, 
  94.         // draw the Thing windows, and the intro screen.
  95.         batch = NO;
  96.         textmode(C4350);
  97.         _setcursortype(_NOCURSOR);
  98.         WipeScreen();
  99. #ifdef HAVE_MOUSE
  100.         InitMouse();
  101. #endif
  102.         Printfunc[THING]();
  103.         redraw = NOT;
  104.         Printintro();
  105.     }
  106.  
  107.     while (ExitLoop == NO)
  108.     {
  109.         // Redraw the correct screen
  110.         if (redraw != NOT) {
  111.             if (redraw == ALL)
  112.                 WipeScreen();
  113.  
  114.             // Draw the correct screen according to current mode
  115.             Printfunc[mode]();
  116.             redraw = NOT;
  117.         }
  118.  
  119.         // Highlight the current field
  120.         Highlight(NHILIT);
  121.  
  122.         // The Process functions return a YES if the user is exiting...
  123.         if (Waitforevent(NO))
  124.             ExitLoop = ProcessKeypress();
  125. #ifdef HAVE_MOUSE
  126.         else
  127.             ExitLoop = ProcessMouse();
  128. #endif
  129.  
  130.         // Close the mouse, clear the screen, print exiting message.
  131.         if (ExitLoop == YES)
  132.         {
  133. #ifdef HAVE_MOUSE
  134.             CloseMouse();
  135. #endif
  136.             textmode(C80);
  137.             cls();
  138.             gotoxy(1,1);
  139.             textattr(0);
  140.             tty_raw(NO);
  141.             puts("Exiting...");
  142.             puts("Bye!");
  143.         }
  144.     }
  145.  
  146.     // Delete allocated memory
  147.     delete[] thingdata;
  148.     delete[] sounddata;
  149.     delete[] framedata;
  150.     delete[] spritedata;
  151.     delete[] maxammodata;
  152.     delete[] perammodata;
  153.     delete[] weapondata;
  154.     delete[] textdatap;
  155.  
  156.     // Close open files
  157.     fclose(doomexefp);
  158.     fclose(doomwadfp);
  159.     fclose(doombakfp);
  160.  
  161.     return 0;
  162. }
  163.  
  164. // Aborts program when out of memory, and asks if the user wants to
  165. // write the changes first.  I hate it when DEU just crashes!
  166.  
  167. void AbortProg(char *func)
  168. {
  169.     int result;
  170.  
  171.     // Crash to text mode, let the user know what happened, and how much
  172.     // memory is still left.
  173.     clearscreen(0, ' ');
  174.     textmode(C80);
  175.     gotoxy(1,1);
  176.     textattr(0);
  177.     printf("Out of memory %s!\n", func);
  178.  
  179.     // If there are changes to write, ask the user if he/she wants to write
  180.     // them.  This *should* work even if we have 0 memory free.
  181.     if (changes == YES)
  182.     {
  183.         puts("Do you want to write all changes to the exe file?  ");
  184.         result = getch();
  185.         if (tolower(result) == 'y')
  186.         {
  187.             Writedoom();
  188.             puts("Changes written.\n");
  189.         }
  190.         else
  191.             puts("Changes not written.\n");
  192.     }
  193.  
  194.     puts("Have a nice day.  Try again later with a bit more memory");
  195.     puts("free...");
  196.     exit(1);
  197. }
  198.  
  199. // Changes to a new editing mode
  200.  
  201. void Changemode(EModes newmode)
  202. {
  203.     // Redraw only the data if the person tries to switch the mode he's
  204.     // currently in.
  205.     if (newmode != mode)
  206.         redraw = ALL;
  207.     else
  208.         redraw = ALLDATA;
  209.  
  210.     mode = newmode;
  211.  
  212.     // Verify that the current item is onscreen for the different
  213.     // lists... ie, if we're on Frame #562, make sure that one is somewhere
  214.     // on the screen.  Adjust TOPROW accordingly.
  215.     if (global[mode][CUR] < global[mode][TOPROW] ||
  216.          global[mode][CUR] > global[mode][TOPROW] + 37)
  217.     {
  218.         if (global[mode][CUR] < 18)
  219.             global[mode][TOPROW] = 0;
  220.         else if (global[mode][CUR] > global[mode][GMAX]-global[mode][GMIN]-37)
  221.             global[mode][TOPROW] = global[mode][GMAX]-global[mode][GMIN]-37;
  222.         else
  223.             global[mode][TOPROW] = global[mode][CUR] - 18;
  224.     }
  225.     else if (redraw == ALLDATA)
  226.         redraw = NOT;
  227. }
  228.  
  229. // Copies from one object to another.
  230.  
  231. int Getcopyinfo(void)
  232. {
  233.     int minnum = global[mode][GMIN];
  234.     int fromnum, tonum;
  235.     char buffer[40];
  236.     char temp[40];
  237.  
  238.     // Text strings can't be copied due to the stringent length restrictions.
  239.     // It's possible to, but very very few of the strings are = in length.
  240.     if (mode == TEXT_EDIT)
  241.     {
  242.         Printwindow("Text strings cannot be copied.", ERROR);
  243.         return -1;
  244.     }
  245.  
  246.     sprintf(buffer, "Enter the %s number to copy from:", objnames[mode]);
  247.     if (Printinputwindow(temp, buffer, LONGINT, 12) == -1)
  248.         return -1;
  249.  
  250.     // Verify the from number to make sure it's not invalid.
  251.     fromnum = atoi(temp);
  252.     if (fromnum < minnum || fromnum > global[mode][GMAX])
  253.     {
  254.         sprintf(buffer, "Invalid %s number!", objnames[mode]);
  255.         Printwindow(buffer, ERROR);
  256.         return -1;
  257.     }
  258.  
  259.     sprintf(buffer, "Enter the %s number to copy to:", objnames[mode]);
  260.     if (Printinputwindow(temp, buffer, LONGINT, 12) == -1)
  261.         return -1;
  262.  
  263.     // Verify the to number to make sure it's not invalid.
  264.     tonum = atoi(temp);
  265.     if (tonum < minnum || tonum > global[mode][GMAX])
  266.     {
  267.         sprintf(buffer, "Invalid %s number!", objnames[mode]);
  268.         Printwindow(buffer, ERROR);
  269.         return -1;
  270.     }
  271.  
  272.     // OK, the dope is trying to copy something over itself.
  273.     if (fromnum == tonum)
  274.     {
  275.         sprintf(buffer, "Duplicate %s number!", objnames[mode]);
  276.         Printwindow(buffer, ERROR);
  277.         return -1;
  278.     }
  279.  
  280.     // Compensate for different starting indices in the objects, ie, Things
  281.     // start at #1, whereas Frames start at #0.
  282.     tonum -= minnum;
  283.     fromnum -= minnum;
  284.  
  285.     // And do the copy...
  286.     switch (mode)
  287.     {
  288.         case THING_EDIT:
  289.         case THING_LIST:
  290.             memcpy(&thingdata[tonum], &thingdata[fromnum], size[THING][version]);
  291.             break;
  292.         case FRAME_EDIT:
  293.             memcpy(&framedata[tonum], &framedata[fromnum], size[FRAME][version]);
  294.             break;
  295.         case AMMO_EDIT:
  296.             memcpy(&weapondata[tonum], &weapondata[fromnum], size[WEAPON][version]);
  297.             break;
  298.         case SPRITE_EDIT:
  299.             memcpy(&spritedata[tonum], &spritedata[fromnum], size[SPRITE][version]);
  300.             break;
  301.         case SOUND_EDIT:
  302.             memcpy(&sounddata[tonum], &sounddata[fromnum], size[SOUND][version]);
  303.             break;
  304.     }
  305.     return 0;
  306. }
  307.  
  308. // Go to a given object for any mode
  309.  
  310. int GotoObject(int firstdigit)
  311. {
  312.     char prompt[30];
  313.     char buffer[20];
  314.     long num;
  315.     int min = global[mode][GMIN];
  316.     EBool error = NO;
  317.  
  318.     sprintf(prompt, "Enter a new %s number:", objnames[mode]);
  319.     if (Printinputwindow(buffer, prompt, LONGINT, 0, firstdigit) == -1)
  320.         return -1;
  321.  
  322.     // Check for negative numbers, at least.
  323.     num = atol(buffer);
  324.     if (num < 0)
  325.     {
  326.         Printwindow("Negative numbers are invalid.", ERROR);
  327.         return -1;
  328.     }
  329.  
  330.     // Make sure it's a valid object to go to.  Note that for the THING_EDIT
  331.     // window we need to do a special return of the correct number to go to.
  332.     // All other modes, just go there.
  333.     switch (mode)
  334.     {
  335.         case THING_EDIT:
  336.             if (num > global[THING][GMAX])
  337.                 error = YES;
  338.             else
  339.                 return num - min;
  340.             break;
  341.         case FRAME_EDIT:
  342.         case AMMO_EDIT:
  343.         case SOUND_EDIT:
  344.         case SPRITE_EDIT:
  345.         case THING_LIST:
  346.             if (num > global[mode][GMAX])
  347.                 error = YES;
  348.             else
  349.                 global[mode][CUR] = (int)(num - min);
  350.             break;
  351.         case TEXT_EDIT:
  352.             if (num > size[TXT][version])
  353.                 error = YES;
  354.             else
  355.                 global[mode][CUR] = Gettextnum(num+toff[version]);
  356.             break;
  357.     }
  358.  
  359.     // Invalid number to go to
  360.     if (error == YES)
  361.     {
  362.         Printwindow("That value is too high!", ERROR);
  363.         return -1;
  364.     }
  365.  
  366.     // Make it so.
  367.     Changemode(mode);
  368.  
  369.     return 0;
  370. }
  371.  
  372. // Highlights the current field (equivalent to unhighlighting if the
  373. // NORMAL attribute is given).
  374.  
  375. void Highlight(unsigned char attribute)
  376. {
  377.     int ref = posinfo[mode][0] + global[mode][FIELD] - 1;
  378.     int i, row;
  379.  
  380.     if (mode == THING_EDIT || mode == AMMO_EDIT)
  381.         row = Fielddata[ref][0];
  382.     else
  383.         row = global[mode][CUR] - global[mode][TOPROW] + 7;
  384.  
  385.     // Check the super duper master array of highlight locations, and
  386.     // change the color of whatever information is there accordingly.
  387.     for (i=Fielddata[ref][3]-1; i < Fielddata[ref][4]; i++)
  388.         highlight_loc(i+1, row+1, attribute);
  389. }
  390.  
  391. // Handles the command line arguments.  Also opens the doom.exe file.
  392. // Current verification of doom.exe is the file size.
  393.  
  394. int Parsecommandline(int argc, char *argv[])
  395. {
  396.     int i = 1;
  397.     EBool quit = NO;
  398.     char buffer[160] = "";
  399.  
  400.     Printtextintro();
  401.  
  402.     // If there was a command-line path for doom specified, make sure
  403.     // the path ends in a backslash.
  404.     if (argc > 1 && argv[1][0] != '-')
  405.     {
  406.         strcpy(buffer, argv[i++]);
  407.         if (buffer[strlen(buffer)-1] != '\\' && strlen(buffer) != 0)
  408.             strcat(buffer, "\\");
  409.     }
  410.  
  411.     if (GetDoomFiles(buffer) == -1)
  412.         return -1;
  413.  
  414.     // Verify size
  415.     fseek(doomexefp, 0, SEEK_END);
  416.     if (ftell(doomexefp) == SIZE1_12)
  417.     {
  418.         version = DOOM1_2;
  419.         truever = DOOM1_12;
  420.         puts("Using registered Doom v1.2.");
  421.     }
  422.     else if (ftell(doomexefp) == SIZE1_16)
  423.     {
  424.         version = DOOM1_6;
  425.         truever = DOOM1_16;
  426.         puts("Using registered Doom v1.666.");
  427.     }
  428.     else if (ftell(doomexefp) == SIZE2_16)
  429.     {
  430.         version = DOOM2_0;
  431.         truever = DOOM2_16;
  432.         puts("Using Doom 2, Hell On Earth, v1.666.");
  433.     }
  434.     else if (ftell(doomexefp) == SIZE2_17)
  435.     {
  436.         version = DOOM1_6;
  437.         truever = DOOM2_17;
  438.         puts("Using Doom 2, Hell On Earth, v1.7.");
  439.     }
  440.     else if (ftell(doomexefp) == SIZE2_17A)
  441.     {
  442.         version = DOOM1_6;
  443.         truever = DOOM2_17A;
  444.         puts("Using Doom 2, Hell On Earth, v1.7a.");
  445.     }
  446.     else if (ftell(doomexefp) == SIZE2_19)
  447.     {
  448.         version = DOOM1_9;
  449.         truever = DOOM2_19;
  450.         puts("Using registered Doom v1.9.");
  451.     }
  452.     else if (ftell(doomexefp) == SIZE2_18)
  453.     {
  454.         puts("\nDoom v1.8 exe found...  DeHackEd v2.3 doesn't support Doom 1.8.");
  455.         puts("Upgrade to version 1.9, and you'll be all set!");
  456.         return -1;
  457.     }
  458.     else if (ftell(doomexefp) == SIZEX_18) {
  459.         version = LNX_X18;
  460.         truever = DOOMX_18;
  461.         Lnx_DOOM = YES;
  462.         puts("Using registered Linux X11 Doom v1.9.");
  463.     }
  464.     else if (ftell(doomexefp) == SIZES_18) {
  465.         version = LNX_S18;
  466.         truever = DOOMS_18;
  467.         Lnx_DOOM = YES;
  468.         puts("Using registered Linux SVGA Doom v1.9.");
  469.     }
  470.     else if (ftell(doomexefp) == SIZE_SGI16) {
  471.         puts("SGI X11 Doom version 1.666 not supported!\n");
  472.         return -1;
  473.     }
  474.     else if (ftell(doomexefp) == SIZE_SGI18) {
  475.         version = SGI_X18;
  476.         truever = DOOM_SGI;
  477.         puts("Using registered SGI X11 Doom v1.9.");
  478.     }
  479.     else if (ftell(doomexefp) == doomsize)
  480.         printf("Using user-specified Doom size, %ld.", doomsize);
  481.     else
  482.     {
  483.         puts("Unknown Doom exe file size!");
  484.         puts("You may have a modified Doom exe file, or you are using an");
  485.         puts("unknown version of Doom.  Do you wish to continue?");
  486.         puts("If you are not positive about this, answer no!");
  487.         char key = getch();
  488.         if (tolower(key) != 'y')
  489.             return -1;
  490.     }
  491.  
  492.     // OK, load the stuff
  493.     Loaddoom(doomexefp);
  494.  
  495.     // Set the highest object number for each object.  This is necessary
  496.     // for Doom because we are dealing with multiple version numbers and
  497.     // have to watch out in case the user specifies a strange version number
  498.     // manually.
  499.     global[0][GMAX] = numobj[THING][version];
  500.     global[1][GMAX] = numobj[FRAME][version]  - 1;
  501.     global[2][GMAX] = numobj[WEAPON][version];
  502.     global[3][GMAX] = numobj[SOUND][version];
  503.     global[4][GMAX] = numobj[SPRITE][version] - 1;
  504.     global[5][GMAX] = numobj[TXT][version]   - 1;
  505.     global[6][GMAX] = numobj[THING][version]  - 1;
  506.  
  507.     // Parse all the command line args
  508.     for (; i<argc; i++)
  509.     {
  510.         if (stricmp(argv[i], "-load") == 0)
  511.         {
  512.             strcpy(buffer, argv[++i]);
  513.             printf("Loading patch file:  %s\n\t", buffer);
  514.             if (Loadpatch(buffer) != ERROR)
  515.                 Writedoom();
  516.             quit = YES;
  517.         }
  518.         else if (stricmp(argv[i], "-save") == 0)
  519.         {
  520.             int x, y, result;
  521.  
  522.             strcpy(buffer, argv[++i]);
  523.             printf("Saving patch file:  %s\n\t", buffer);
  524.             wherexy(&x, &y);
  525.  
  526.             result = Savepatch(buffer, NO);
  527.             if (result == -1)
  528.             {
  529.                 cputs("File exists!  Overwrite?  ");
  530.                 result = getch();
  531.                 gotoxy(x, y);
  532.                 clreol();
  533.                 if (tolower(result) != 'y')
  534.                     strcpy(buffer, "Write canceled.");
  535.                 else
  536.                     Savepatch(buffer, YES);
  537.             }
  538.             puts(buffer);
  539.             quit = YES;
  540.         }
  541.         else if (stricmp(argv[i], "-reload") == 0)
  542.         {
  543.             Loaddoom(doombakfp);
  544.             Writedoom();
  545.             printf("Doom data reloaded from %s.\n", doombak);
  546.             quit = YES;
  547.         }
  548.         else
  549.         {
  550.             printf("  Cannot parse command \"%s\"!\n", argv[i]);
  551.             Printoptions();
  552.             return -1;
  553.         }
  554.     }
  555.  
  556.     // quit will be set if we are working on some command line arguments
  557.     // and don't actually want to edit interactively.
  558.     if (quit)
  559.         return -1;
  560.     else
  561.         return 0;
  562. }
  563.  
  564. // Run Doom.  This sucker's tricky.  Probably the wrong way to do it too,
  565. // but I'm not sure of a better way.
  566.  
  567. int RunExe(void)
  568. {
  569.     char buffer[80];
  570.     char *argv[20];
  571.     int i=2, j;
  572.  
  573.     // Check if the doompath actually exists.
  574.     if (chdir(doompath) == -1)
  575.     {
  576.         sprintf(buffer, "Could not switch to %s!", doompath);
  577.         Printwindow(buffer, ERROR);
  578.         return -1;
  579.     }
  580.  
  581.     // Init 'em to NULL, if that helps at all.  Hopefully prevents garbage
  582.     // arguments from getting passed to Doom.
  583.     for (j=0; j<20; j++)
  584.         argv[j] = NULL;
  585.  
  586.     strcpy(buffer, doomargs);
  587.     argv[0] = doomexe;
  588.     argv[1] = buffer;
  589.  
  590.     // Parse the doomargs into separate arguments.
  591.     // Not sure if this is necessary, but it seems to work.
  592.     for (j=0; j<strlen(doomargs); j++)
  593.     {
  594.         if (buffer[j] == ' ' || buffer[j] == '\t')
  595.         {
  596.             buffer[j] = 0;
  597.  
  598.             if (argv[i-1] == &(buffer[j]))
  599.                 argv[i-1] = &(buffer[j+1]);
  600.             else
  601.             {
  602.                 argv[i] = &(buffer[j+1]);
  603.                 i++;
  604.             }
  605.         }
  606.         else if (buffer[j] == '\r' || buffer[j] == '\n')
  607.             break;
  608.     }
  609.     buffer[j] = 0;
  610.  
  611.     // Change the screen mode, close files, etc.
  612.     textmode(C80);
  613. #ifdef HAVE_MOUSE
  614.     CloseMouse();
  615. #endif
  616.     fclose(doomexefp);
  617.     fclose(doomwadfp);
  618.     fclose(doombakfp);
  619.     tty_raw(NO);
  620.  
  621.     // Now try to actually run it.
  622.     spawn(doomexe, argv);
  623.  
  624.     // Set things up again.  re-open Doom files, init mouse, etc.
  625.     tty_raw(YES);
  626.     if (GetDoomFiles("") == -1)
  627.         exit (1);
  628. #ifdef HAVE_MOUSE
  629.     InitMouse();
  630. #endif
  631.     textmode(C4350);
  632.     _setcursortype(_NOCURSOR);
  633.     chdir(curdir);
  634.     redraw = ALL;
  635.  
  636.     return 0;
  637. }
  638.  
  639. // Updates an ammo field with new information.
  640.  
  641. int Updateammo(void)
  642. {
  643.     char order[5] = {BOB1FRAME, BOB2FRAME, BOB3FRAME, SHOOTFRAME, FIREFRAME};
  644.     int curfield = global[AMMO_EDIT][FIELD];
  645.     int curnum = global[AMMO_EDIT][CUR];
  646.     char buffer[20];
  647.     char prompt[20];
  648.     long num;
  649.  
  650.     // If this is a field that shouldn't be edited, return.  Ammo needs a
  651.     // special check, because the ammo can't be edited if it's "N/A", not
  652.     // a know ammo value.
  653.     if (curfield < 1 || curfield > 8 ||
  654.         ((weapondata[curnum][AMMOTYPE] >= numobj[AMMO][version]) &&
  655.          (curfield == 2 || curfield == 3)))
  656.         return -1;
  657.  
  658.     // Get the new value
  659.     sprintf(prompt, "%s:", fullwepfields[curfield-1]);
  660.     if (Printinputwindow(buffer, prompt, LONGINT, 0) == -1)
  661.         return -1;
  662.  
  663.     num = atol(buffer);
  664.  
  665.     // Update the correct ammo or weapon data array with the new info.
  666.     if (curfield == 1)
  667.         weapondata[curnum][AMMOTYPE] = num;
  668.     else if (curfield == 2)
  669.         maxammodata[weapondata[curnum][AMMOTYPE]] = num;
  670.     else if (curfield == 3)
  671.         perammodata[weapondata[curnum][AMMOTYPE]] = num;
  672.     else
  673.         weapondata[curnum][order[curfield-4]] = num;
  674.  
  675.     return 0;
  676. }
  677.  
  678. // Updates a Frame record and field with new info.
  679.  
  680. int Updateframe(void)
  681. {
  682.     char order[6] = {SPRITENUM, SPRITESUB, 0, NEXTFRAME, DURATION, ACTIONPTR};
  683.     int curfield = global[FRAME_EDIT][FIELD];
  684.     int curnum = global[FRAME_EDIT][CUR];
  685.     char buffer[20];
  686.     char prompt[20];
  687.  
  688.     // Can't edit an invalid field
  689.     if (curfield < 1 || curfield > 6)
  690.         return -1;
  691.  
  692.     curfield--;
  693.  
  694.    // Don't print the input box if we're on the "Bright Sprite" field.
  695.     if (curfield != 2)
  696.     {
  697.         sprintf(prompt, "%s:", framefields[order[curfield]]);
  698.         if (Printinputwindow(buffer, prompt, LONGINT, 0) == -1)
  699.             return -1;
  700.     }
  701.  
  702.     if ((curfield == SPRITESUB) && (framedata[curnum][SPRITESUB] & (1L << 15)))
  703.         framedata[curnum][SPRITESUB] = (atol(buffer)) ^ (1L << 15);
  704.     else if (curfield == 2)
  705.         framedata[curnum][SPRITESUB] ^= (1L << 15);
  706.     else
  707.         framedata[curnum][order[curfield]] = atol(buffer);
  708.  
  709.     return 0;
  710. }
  711.  
  712. // Updates a Sound record and field with new info
  713.  
  714. int Updatesound(void)
  715. {
  716.     int curfield = global[SOUND_EDIT][FIELD];
  717.     int curnum = global[SOUND_EDIT][CUR];
  718.     char order[3] = {TEXTP, ZERO_ONE, VALUE};
  719.     char buffer[20];
  720.     char prompt[20];
  721.  
  722.     if (curfield < 1 || curfield > 3)
  723.         return -1;
  724.  
  725.     sprintf(prompt, "%s:", soundfields[order[curfield-1]]);
  726.     if (Printinputwindow(buffer, prompt, LONGINT, 0) == -1)
  727.         return -1;
  728.  
  729.     curfield--;
  730.  
  731.     if (curfield == 0)
  732.         sounddata[curnum][TEXTP] = atol(buffer) + toff[version];
  733.     else
  734.         sounddata[curnum][order[curfield]] = atol(buffer);
  735.  
  736.     return 0;
  737. }
  738.  
  739. // Updates the Sprite array with new info
  740.  
  741. int Updatesprite(void)
  742. {
  743.     char buffer[20];
  744.  
  745.     if (Printinputwindow(buffer, "Enter a new value:", LONGINT, 0) == -1)
  746.         return -1;
  747.  
  748.     spritedata[global[mode][CUR]] = atol(buffer) + toff[version];
  749.  
  750.     return 0;
  751. }
  752.  
  753. // Wrapper function to update the text section
  754.  
  755. int Updatetext(void)
  756. {
  757.     return Inputtext(NO);
  758. }
  759.  
  760. // Updates a Thing record with new info to a certain field from the Thinglist.
  761.  
  762. int Updatethingl(void)
  763. {
  764.     char order[4] = {IDNUM, HP, SPEED, MISSILEDAMAGE};
  765.     int curfield = global[THING_LIST][FIELD];
  766.     int curnum = global[THING_LIST][CUR];
  767.     char buffer[20];
  768.     char prompt[20];
  769.  
  770.     if (curfield < 1 || curfield > 4)
  771.         return -1;
  772.  
  773.     curfield--;
  774.  
  775.     sprintf(prompt, "%s:", thingfields[order[curfield]]);
  776.     if (Printinputwindow(buffer, prompt, LONGINT, 0) == -1)
  777.         return -1;
  778.  
  779.     if (curfield == 2 && ((curnum != 0) && (thingdata[curnum][BITS] & 65536L)))
  780.         thingdata[curnum][order[curfield]] = (atol(buffer)) << 16;
  781.     else
  782.         thingdata[curnum][order[curfield]] = atol(buffer);
  783.  
  784.     return 0;
  785. }
  786.  
  787. // Updates a Thing record with new info to a certain field.
  788.  
  789. int Updatethings(void)
  790. {
  791.     int curfield = global[THING_EDIT][FIELD];
  792.     int curnum = global[THING_EDIT][CUR];
  793.     char buffer[20];
  794.     char prompt[20];
  795.  
  796.     // Return on an invalid field
  797.     if (curfield < 1 || curfield > 55 ||
  798.         (curfield == 24 && version == DOOM1_2))
  799.         return -1;
  800.  
  801.     curfield--;
  802.  
  803.     // Check if this is a non-bit field that we're editing
  804.     if (curfield < 23)
  805.     {
  806.         // If so, print the prompt and get a new value.
  807.         sprintf(prompt, "%s:", thingfields[thingorder[curfield]]);
  808.         if (Printinputwindow(buffer, prompt, LONGINT, 0) == -1)
  809.             return -1;
  810.  
  811.         // Replace the Thing values, being very careful of the fields that
  812.         // are multiplied by 65536.
  813.         if (thingorder[curfield] == CWIDTH || thingorder[curfield] == CHEIGHT ||
  814.             ((thingorder[curfield] == SPEED) &&
  815.             ((curnum != 0) && (thingdata[curnum][BITS] & 65536L))))
  816.             thingdata[curnum][thingorder[curfield]] = (atol(buffer)) << 16;
  817.         else
  818.             thingdata[curnum][thingorder[curfield]] = atol(buffer);
  819.     }
  820.     else
  821.         // Otherwise just update the correct bit in the correct Bits field
  822.         // by XORing it with itself.
  823.         thingdata[curnum][BITS] ^= (1L << (curfield-23));
  824.  
  825.     return 0;
  826. }
  827.